package com.sl.au.controller;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.sl.au.entity.Account;
import com.sl.au.entity.DateQueryItem;
import com.sl.au.entity.DoubleQueryItem;
import com.sl.au.entity.IntegerQueryItem;
import com.sl.au.entity.M2R;
import com.sl.au.entity.Module;
import com.sl.au.entity.NumQueryItem;
import com.sl.au.entity.Option;
import com.sl.au.entity.User;
import com.sl.au.service.AccountService;
import com.sl.au.service.M2RService;
import com.sl.au.service.ModuleService;
import com.sl.au.service.OptionService;
import com.sl.utils.DataConverter;
import com.sl.utils.NumberFormatToChinese;

import net.coobird.thumbnailator.Thumbnails;

public class BaseController implements ErrorController {

	private static final String PATH = "/error";
	protected static Module module = null;
	@Value("${web.upload-path}")
	protected String fileUploadPath;

	public String getFileUploadPath() {
		return fileUploadPath;
	}

	public void setFileUploadPath(String fileUploadPath) {
		this.fileUploadPath = fileUploadPath;
	}

	// datasourceName
	@Value("${web.datasourceName}")
	protected String datasourceName;

	public String getDatasourceName() {
		return datasourceName;
	}

	public void setDatasourceName(String datasourceName) {
		this.datasourceName = datasourceName;
	}

	//online
	@Value("${web.online}")
	protected double online;
	
	public double getOnline() {
		return online;
	}

	public void setOnline(double online) {
		this.online = online;
	}

	// verification
	@Value("${verification.url}")
	protected String verificationUrl;

	public String getverificationUrl() {
		return verificationUrl;
	}
	@Value("${verification.uid}")
	protected String verificationUser;

	public String getverificationUser() {
		return verificationUser;
	}
	@Value("${verification.pwd}")
	protected String verificationPwd;

	public String getverificationPwd() {
		return verificationPwd;
	}
	@Value("${verification.gwid}")
	protected String verificationGwid;

	public String getverificationGwid() {
		return verificationGwid;
	}

	// 移动端访问带的固定参数
	protected final String DEVICE = "mobile";
	// 移动端访问带的参数
	private String identify;

	public String getIdentify() {
		return identify;
	}

	@Autowired
	HttpServletRequest request;

	@Autowired
	M2RService m2rService;
	@Autowired
	ModuleService moduleService;
	@Autowired
	AccountService accountService;

	public ModelAndView createLayoutView(String rightViewName) {
		ModelAndView mv = new ModelAndView("layout/layout");
		mv.addObject("rightViewName", rightViewName);
		mv.addObject("canReadCustomer", this.canReadCustomer());
		return mv;
	}

	public ModelAndView createSingleView(String rightViewName) {
		ModelAndView mv = new ModelAndView(rightViewName);
		return mv;
	}
	
	public Map<String, Object> sendMessage(String phoneList,String content){
		Map<String, Object> map = new HashMap<String, Object>();
		// 消息推送通知
				try {
					// 创建一个URL对象
					URL targetUrl = new URL(this.getverificationUrl());
					// 从URL对象中获得一个连接对象
					HttpURLConnection conn = (HttpURLConnection) targetUrl.openConnection();
					// 设置请求方式 注意这里的POST或者GET必须大写
					conn.setRequestMethod("POST");
					// 设置POST请求是有请求体的
					conn.setDoOutput(true);
					// 拼接发送的短信内容
					StringBuilder params = new StringBuilder(100).append("type=").append("send").append("&username=")
							.append(this.getverificationUser()).append("&password=").append(this.getverificationPwd())
							.append("&gwid=").append(this.getverificationGwid()).append("&mobile=").append(phoneList)
							.append("&message=").append(content);
					// 写入参数
					conn.getOutputStream().write(params.toString().getBytes(Charset.forName("UTF-8")));
					// 读入响应
					String response = StreamUtils.copyToString(conn.getInputStream(), Charset.forName("UTF-8"));
					// 发送成功 以success开头
					if (response.contains("success")) {
						map.put("code", 1);
					} else {
						map.put("code", -1);
						throw new RuntimeException();
					}
				} catch (Exception e) {
					/*e.printStackTrace();
					throw new RuntimeException("发送短信失败");*/
				}
				// -----------------
				return map;
	}
	/**
     * BASE64Encoder 加密
     * 
     * @param data
     *            要加密的数据
     * @return 加密后的字符串
     */
    public static String encryptBASE64(byte[] data) {
        // BASE64Encoder encoder = new BASE64Encoder();
        // String encode = encoder.encode(data);
        // 从JKD 9开始rt.jar包已废除，从JDK 1.8开始使用java.util.Base64.Encoder
        Encoder encoder = Base64.getEncoder();
        String encode = encoder.encodeToString(data);
        return encode;
    }
	/**
     * BASE64Decoder 解密
     * 
     * @param data
     *            要解密的字符串
     * @return 解密后的byte[]
     * @throws Exception
     */
    public static byte[] decryptBASE64(String data) throws Exception {
        // BASE64Decoder decoder = new BASE64Decoder();
        // byte[] buffer = decoder.decodeBuffer(data);
        // 从JKD 9开始rt.jar包已废除，从JDK 1.8开始使用java.util.Base64.Decoder
        Decoder decoder = Base64.getDecoder();
        byte[] buffer = decoder.decode(data);
        return buffer;
    }
    
 public String saveImgWithBase64(String where,String type,String fileName,String imgStr){
	//对字节数组字符串进行Base64解码并生成图片  
     if (imgStr == null) //图像数据为空  
         return "";  
     try   
     {  
    	 String path = where + type;// + "/" + datePath;
 		File dir = new File(path);// c:/upload/img/inspection/20180203020255
 		if (!dir.exists()) {
 			dir.mkdirs();
 		}
 		FileOutputStream fos = null;
 		path += "/" + (UUID.randomUUID().toString() + fileName);// c:/upload/img/inspection/20180203020255/....png
         //Base64解码  
         byte[] b = decryptBASE64(imgStr);  
         for(int i=0;i<b.length;++i)  
         {  
             if(b[i]<0)  
             {//调整异常数据  
                 b[i]+=256;  
             }  
         }  
         fos = new FileOutputStream(path);      
         fos.write(b);  
         fos.flush();  
         fos.close();  
         path = path.substring(where.length());
         return path;  
     }   
     catch (Exception e)   
     {  
         return "";  
     } 
 }
	/**
	 * 
	 * @param where
	 *            传到磁盘的那个位置
	 * @param type
	 *            上传的目录类型构建,比如巡检类图片
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public String getUploadFilePath(String where, String type, MultipartFile file) {
		/*
		 * SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmm"); String
		 * datePath = sdf.format(new Date());
		 */

		String path = where + type;// + "/" + datePath;
		File dir = new File(path);// c:/upload/img/inspection/20180203020255
		if (!dir.exists()) {
			dir.mkdirs();
		}

		// 获取文件的名称
		String fileName = file.getOriginalFilename();
		if (fileName.contains("/")) {
			String[] sp = fileName.split("/");
			fileName = sp[sp.length - 1];
		}

		InputStream in = null;
		FileOutputStream fos = null;
		path += "/" + (UUID.randomUUID().toString() + fileName);// c:/upload/img/inspection/20180203020255/....png
		try {
			// 获取文件的输入流
			in = file.getInputStream();
			// 将文件写入到磁盘中

			fos = new FileOutputStream(path);
			FileCopyUtils.copy(in, fos);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (fos != null) {
					fos.close();
					fos = null;
				}
				if (in != null) {
					in.close();
					in = null;
				}
			} catch (Exception ex) {
				ex.printStackTrace();
			}
			try {
				commpressPicForScale(path, path, 300, 0.8);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		path = path.substring(where.length());
		return path;
	}

	/**
	 * 
	 * @param where
	 *            传到磁盘的那个位置
	 * @param type
	 *            上传的目录类型构建,比如巡检类图片
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public String getUploadIconFilePath(String where, String type, MultipartFile file) {
		/*
		 * SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmm"); String
		 * datePath = sdf.format(new Date());
		 */

		String path = where + type;// + "/" + datePath;
		File dir = new File(path);// c:/upload/img/inspection/20180203020255
		if (!dir.exists()) {
			dir.mkdirs();
		}

		// 获取文件的名称
		String fileName = file.getOriginalFilename();
		if (fileName.contains("/")) {
			String[] sp = fileName.split("/");
			fileName = sp[sp.length - 1];
		}

		InputStream in = null;
		FileOutputStream fos = null;
		path += "/" + (UUID.randomUUID().toString() + fileName);// c:/upload/img/inspection/20180203020255/....png
		try {
			// 获取文件的输入流
			in = file.getInputStream();
			// 将文件写入到磁盘中

			fos = new FileOutputStream(path);
			FileCopyUtils.copy(in, fos);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (fos != null) {
					fos.close();
					fos = null;
				}
				if (in != null) {
					in.close();
					in = null;
				}
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
		path = path.substring(where.length());
		return path;
	}

	/**
	 * 根据指定大小和指定精度压缩图片
	 * 
	 * @param srcPath
	 *            源图片地址
	 * @param desPath
	 *            目标图片地址
	 * @param desFilesize
	 *            指定图片大小，单位kb
	 * @param accuracy
	 *            精度，递归压缩的比率，建议小于0.9
	 * @return
	 */
	public String commpressPicForScale(String srcPath, String desPath, long desFileSize, double accuracy) {
		if (StringUtils.isEmpty(srcPath) || StringUtils.isEmpty(srcPath)) {
			return null;
		}
		if (!new File(srcPath).exists()) {
			return null;
		}
		try {
			File srcFile = new File(srcPath);
			long srcFileSize = srcFile.length();
			// System.out.println("源图片：" + srcPath + "，大小：" + srcFileSize / 1024
			// + "kb");

			// 1、先转换成jpg
			Thumbnails.of(srcPath).scale(1f).toFile(desPath);
			// 递归压缩，直到目标文件大小小于desFileSize
			commpressPicCycle(desPath, desFileSize, accuracy);

			File desFile = new File(desPath);
			// System.out.println("目标图片：" + desPath + "，大小" + desFile.length() /
			// 1024 + "kb");
			// System.out.println("图片压缩完成！");
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return desPath;
	}

	private void commpressPicCycle(String desPath, long desFileSize, double accuracy) throws IOException {
		File srcFileJPG = new File(desPath);
		long srcFileSizeJPG = srcFileJPG.length();
		// 2、判断大小，如果小于500kb，不压缩；如果大于等于500kb，压缩
		if (srcFileSizeJPG <= desFileSize * 1024) {
			return;
		}
		// 计算宽高
		BufferedImage bim = ImageIO.read(srcFileJPG);
		int srcWdith = bim.getWidth();
		int srcHeigth = bim.getHeight();
		int desWidth = new BigDecimal(srcWdith).multiply(new BigDecimal(accuracy)).intValue();
		int desHeight = new BigDecimal(srcHeigth).multiply(new BigDecimal(accuracy)).intValue();

		Thumbnails.of(desPath).size(desWidth, desHeight).outputQuality(accuracy).toFile(desPath);
		commpressPicCycle(desPath, desFileSize, accuracy);
	}

	/**
	 * 得到当前登录用户账号
	 * 
	 * @return
	 */
	// @Cacheable("account")
	protected Account getMyAccount() {
		Account a = null;
		String crmout = request.getHeader("crm-out");
		String outkey = "D9A61EBF-4CC6-4E49-9561-58A6E34F34DF";
		String userid = request.getHeader("userid");
		if (StringUtils.hasText(crmout) && crmout.equals(outkey) && StringUtils.hasText(userid)) {

			// CRM外部调用
			a = new Account();
			User user = new User();
			user.setId(userid);
			a.setUser(user);

		} else if (this.isMobile()) {
			String accountId = request.getHeader("accountid");
			if (StringUtils.hasText(accountId)) {
				a = accountService.getRepository().getOne(accountId);
			}
		} else
			a = (Account) request.getSession().getAttribute("account");

		return a;
	}

	/**
	 * 在当前SESSION中存储变量
	 * 
	 * @param variableName
	 * @param value
	 */
	protected <T> void addSession(String variableName, T value) {
		request.getSession().setAttribute(variableName, value);
	}

	/**
	 * 从当前SESSION中读取变量
	 * 
	 * @param variableName
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected <T> T getSession(String variableName) {
		T r = null;
		r = (T) request.getSession().getAttribute(variableName);
		return r;
	}

	protected Module getPageModule(String moduleName) {
		Module m = null;
		m = moduleService.getRepository().findByName(moduleName);
		if (null == m)
			return null;
		if (null == this.getMyAccount())
			return null;
		String roleId = this.getMyAccount().getRole().getId();
		M2R m2r = this.m2rService.getRepository().findByRoleIdAndModuleId(roleId, m.getId());
		if (m2r != null) {
			m.setCanAdd(m2r.isAddOnly());
			m.setCanDelete(m2r.isDeleteOnly());
			m.setCanModify(m2r.isModifyOnly());
			m.setCanRead(m2r.isReadOnly());
			m.setCanOther1(m2r.isOther1Only());
			m.setCanOther2(m2r.isOther2Only());
			m.setDataFilter(m2r.getDataFilter());
		}
		return m;
	}

	protected Boolean isMobile() {
		String device = request.getHeader("device");
		return StringUtils.hasText(device) ? device.equals("mobile") : false;
	}

	@RequestMapping(value = PATH)
	public String error() {
		return "出错了";
	}

	@Override
	public String getErrorPath() {
		return PATH;
	}

	protected DateQueryItem getDateQueryItem(String propName) {
		String start = request.getParameter(propName + "StartDate");
		String end = request.getParameter(propName + "EndDate");
		DateQueryItem d = null;
		if (StringUtils.hasText(start)) {
			d = new DateQueryItem();
			d.setStartDate(DataConverter.formatDateYMD(start));
		}
		if (StringUtils.hasText(end)) {
			if (d == null)
				d = new DateQueryItem();
			d.setEndDate(DataConverter.formatDateYMD(end));
		}
		if (null != d) {
			d.setPropertyName(propName);
		}
		return d;
	}

	protected NumQueryItem getNumQueryItem(String propName) {
		String start = request.getParameter(propName + "StartNum");
		String end = request.getParameter(propName + "EndNum");
		NumQueryItem n = new NumQueryItem();
		if (StringUtils.hasText(start)) {
			n.setStartNum(Float.parseFloat(start));
		} else {
			n.setStartNum(0);
		}
		if (StringUtils.hasText(end)) {
			n.setEndNum(Float.parseFloat(end));
		} else {
			n.setEndNum(0);
		}
		if (null != n) {
			n.setPropertyName(propName);
		}
		return n;
	}

	protected IntegerQueryItem getIntegerQueryItem(String propName) {
		String start = request.getParameter(propName + "StartNum");
		String end = request.getParameter(propName + "EndNum");
		IntegerQueryItem n = null;
		if (StringUtils.hasText(start)) {
			n = new IntegerQueryItem();
			n.setStartNum(Integer.parseInt(start));
		} else {
			n = new IntegerQueryItem();
			n.setStartNum(0);
		}
		if (StringUtils.hasText(end)) {
			n.setEndNum(Integer.parseInt(end));
		} else {
			n.setEndNum(0);
		}
		if (null != n) {
			n.setPropertyName(propName);
		}
		return n;
	}

	protected DoubleQueryItem getDoubleQueryItem(String propName) {
		String start = request.getParameter(propName + "StartNum");
		String end = request.getParameter(propName + "EndNum");
		DoubleQueryItem n = null;
		if (StringUtils.hasText(start)) {
			n = new DoubleQueryItem();
			n.setStartNum(Double.parseDouble(start));
		} else {
			n = new DoubleQueryItem();
			n.setStartNum(0.0);
		}
		if (StringUtils.hasText(end)) {
			n.setEndNum(Double.parseDouble(end));
		} else {
			n.setEndNum(0.0);
		}
		if (null != n) {
			n.setPropertyName(propName);
		}
		return n;
	}

	protected Boolean canReadCustomer() {
		Boolean r = false;
		List<Module> modules = this.getMyAccount().getRole().getModules();
		for (Module m : modules) {
			if (m.getTarget().contains("/customer")) {
				r = true;
			}
		}
		return r;
	}

	public Option getLevelOption(int nextLevelValueInt, OptionService optionService, String type) {
		String nextLevelValue = nextLevelValueInt + "";
		Option option = optionService.findByGroupAndExtended1(type, nextLevelValue);
		if (option == null) {// 没有该层级则创建
			option = new Option();
			option.setExtended1(nextLevelValue);
			option.setValue((1 + new Random().nextInt(10)) + "");
			option.setGroup(type);
			option.setTitle(NumberFormatToChinese.toChinese(nextLevelValueInt) + "级");
			optionService.getRepository().save(option);
		}
		return option;

	}

	public String getParentId(String parentId) {
		if (parentId.contains("[") && parentId.contains("]")) {
			int len1 = parentId.indexOf("[");
			int len2 = parentId.indexOf("]");
			parentId = parentId.substring(len1 + 1, len2);
		}
		return parentId;
	}

}
